package state.md5;
//
//import state.util.GameStringUtils;
//import state.util.array.ByteArray;
//import state.util.array.CharArray;
//import state.util.array.IntArray;
//
///**
// * Fast implementation of RSA's MD5 hash generator in Java JDK Beta-2 or higher.
// * <p>
// * Originally written by Santeri Paavolainen, Helsinki Finland 1996.<br>
// * (c) Santeri Paavolainen, Helsinki Finland 1996<br>
// * Many changes Copyright (c) 2002 - 2005 Timothy W Macinta<br>
// * <p>
// * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
// * <p>
// * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details.
// * <p>
// * You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// * <p>
// * See http://www.twmacinta.com/myjava/fast_md5.php for more information on this file and the related files.
// * <p>
// * This was originally a rather straight re-implementation of the reference implementation given in RFC1321 by RSA. It passes the MD5 test suite as defined in RFC1321.
// * <p>
// * Many optimizations made by Timothy W Macinta. Reduced time to checksum a test file in Java alone to roughly half the time taken compared with java.security.MessageDigest (within an intepretter). Also added an optional native method to reduce the time even further. See
// * http://www.twmacinta.com/myjava/fast_md5.php for further information on the time improvements achieved.
// * <p>
// * Some bug fixes also made by Timothy W Macinta.
// * <p>
// * Please note: I (Timothy Macinta) have put this code in the com.twmacinta.util package only because it came without a package. I was not the the original author of the code, although I did optimize it (substantially) and fix some bugs.
// * <p>
// * This Java class has been derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm and its reference implementation.
// * <p>
// * This class will attempt to use a native method to quickly compute checksums when the appropriate native library is available. On Linux, this library should be named "MD5.so" and on Windows it should be named "MD5.dll". The code will attempt to locate the library in the following locations in the
// * order given:
// * 
// * <ol>
// * <li>The path specified by the system property "com.twmacinta.util.MD5.NATIVE_LIB_FILE" (be sure to include "MD5.so" or "MD5.dll" as appropriate at the end of the path).
// * <li>A platform specific directory beneath the "lib/arch/" directory. On Linux for x86, this is "lib/arch/linux_x86/". On Windows for x86, this is "lib/arch/win32_x86/".
// * <li>Within the "lib/" directory.
// * <li>Within the current directory.
// * </ol>
// * 
// * <p>
// * If the library is not found, the code will fall back to the default (slower) Java code.
// * <p>
// * As a side effect of having the code search for the native library, SecurityExceptions might be thrown on JVMs that have a restrictive SecurityManager. The initialization code attempts to silently discard these exceptions and continue, but many SecurityManagers will attempt to notify the user
// * directly of all SecurityExceptions thrown. Consequently, the code has provisions for skipping the search for the native library. Any of these provisions may be used to skip the search as long as they are performed <i>before</i> the first instance of a com.twmacinta.util.MD5 object is constructed
// * (note that the convenience stream objects will implicitly create an MD5 object).
// * <p>
// * The first option is to set the system property "com.twmacinta.util.MD5.NO_NATIVE_LIB" to "true" or "1". Unfortunately, SecurityManagers may also choose to disallow system property setting, so this won't be of use in all cases.
// * <p>
// * The second option is to call com.twmacinta.util.MD5.initNativeLibrary(true) before any MD5 objects are constructed.
// * 
// * @author Santeri Paavolainen <sjpaavol@cc.helsinki.fi>
// * @author Timothy W Macinta (twm@alum.mit.edu) (optimizations and bug fixes)
// */
public class MD5 {
//
//  private static final String HEX_CHARS = "0123456789abcdef";
//  private MD5State state = null;
//  private MD5State finals = null;
//  private static final ByteArray padding = new ByteArray( new byte[]{(byte) 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 64);
//
//  /*
//   * len += shift; for (int i = 0; shift < len; i++, shift += 4) { out[i] =
//   * ((int) (buffer[shift] & 0xff)) | (((int) (buffer[shift + 1] & 0xff)) << 8)
//   * | (((int) (buffer[shift + 2] & 0xff)) << 16) | (((int) buffer[shift + 3])
//   * << 24); }
//   */
//  private void decode(final ByteArray buffer, final int shift, final IntArray out1) {
//    // TODO: disable Md5
////    out1.array[0] = (buffer.array[shift] & 0xff) | ((buffer.array[shift + 1] & 0xff) << 8) | ((buffer.array[shift + 2] & 0xff) << 16) | (buffer.array[shift + 3] << 24);
////    out1.array[1] = (buffer.array[shift + 4] & 0xff) | ((buffer.array[shift + 5] & 0xff) << 8) | ((buffer.array[shift + 6] & 0xff) << 16) | (buffer.array[shift + 7] << 24);
////    out1.array[2] = (buffer.array[shift + 8] & 0xff) | ((buffer.array[shift + 9] & 0xff) << 8) | ((buffer.array[shift + 10] & 0xff) << 16) | (buffer.array[shift + 11] << 24);
////    out1.array[3] = (buffer.array[shift + 12] & 0xff) | ((buffer.array[shift + 13] & 0xff) << 8) | ((buffer.array[shift + 14] & 0xff) << 16) | (buffer.array[shift + 15] << 24);
////    out1.array[4] = (buffer.array[shift + 16] & 0xff) | ((buffer.array[shift + 17] & 0xff) << 8) | ((buffer.array[shift + 18] & 0xff) << 16) | (buffer.array[shift + 19] << 24);
////    out1.array[5] = (buffer.array[shift + 20] & 0xff) | ((buffer.array[shift + 21] & 0xff) << 8) | ((buffer.array[shift + 22] & 0xff) << 16) | (buffer.array[shift + 23] << 24);
////    out1.array[6] = (buffer.array[shift + 24] & 0xff) | ((buffer.array[shift + 25] & 0xff) << 8) | ((buffer.array[shift + 26] & 0xff) << 16) | (buffer.array[shift + 27] << 24);
////    out1.array[7] = (buffer.array[shift + 28] & 0xff) | ((buffer.array[shift + 29] & 0xff) << 8) | ((buffer.array[shift + 30] & 0xff) << 16) | (buffer.array[shift + 31] << 24);
////    out1.array[8] = (buffer.array[shift + 32] & 0xff) | ((buffer.array[shift + 33] & 0xff) << 8) | ((buffer.array[shift + 34] & 0xff) << 16) | (buffer.array[shift + 35] << 24);
////    out1.array[9] = (buffer.array[shift + 36] & 0xff) | ((buffer.array[shift + 37] & 0xff) << 8) | ((buffer.array[shift + 38] & 0xff) << 16) | (buffer.array[shift + 39] << 24);
////    out1.array[10] = (buffer.array[shift + 40] & 0xff) | ((buffer.array[shift + 41] & 0xff) << 8) | ((buffer.array[shift + 42] & 0xff) << 16) | (buffer.array[shift + 43] << 24);
////    out1.array[11] = (buffer.array[shift + 44] & 0xff) | ((buffer.array[shift + 45] & 0xff) << 8) | ((buffer.array[shift + 46] & 0xff) << 16) | (buffer.array[shift + 47] << 24);
////    out1.array[12] = (buffer.array[shift + 48] & 0xff) | ((buffer.array[shift + 49] & 0xff) << 8) | ((buffer.array[shift + 50] & 0xff) << 16) | (buffer.array[shift + 51] << 24);
////    out1.array[13] = (buffer.array[shift + 52] & 0xff) | ((buffer.array[shift + 53] & 0xff) << 8) | ((buffer.array[shift + 54] & 0xff) << 16) | (buffer.array[shift + 55] << 24);
////    out1.array[14] = (buffer.array[shift + 56] & 0xff) | ((buffer.array[shift + 57] & 0xff) << 8) | ((buffer.array[shift + 58] & 0xff) << 16) | (buffer.array[shift + 59] << 24);
////    out1.array[15] = (buffer.array[shift + 60] & 0xff) | ((buffer.array[shift + 61] & 0xff) << 8) | ((buffer.array[shift + 62] & 0xff) << 16) | (buffer.array[shift + 63] << 24);
//  }
//
//  private void transform(MD5State state1, ByteArray buffer, int shift, IntArray decode_buf) {
//    int a = state1.state.get(0), b = state1.state.get(1), c = state1.state.get(2), d = state1.state.get(3); 
//    IntArray x = decode_buf;
//
//    decode(buffer, shift, decode_buf);
//
//    /* Round 1 */
// // TODO: disable Md5
////    a += ((b & c) | (~b & d)) + x.array[0] + 0xd76aa478; /* 1 */
////    a = ((a << 7) | (a >>> 25)) + b;
////    d += ((a & b) | (~a & c)) + x.array[1] + 0xe8c7b756; /* 2 */
////    d = ((d << 12) | (d >>> 20)) + a;
////    c += ((d & a) | (~d & b)) + x.array[2] + 0x242070db; /* 3 */
////    c = ((c << 17) | (c >>> 15)) + d;
////    b += ((c & d) | (~c & a)) + x.array[3] + 0xc1bdceee; /* 4 */
////    b = ((b << 22) | (b >>> 10)) + c;
////
////    a += ((b & c) | (~b & d)) + x.array[4] + 0xf57c0faf; /* 5 */
////    a = ((a << 7) | (a >>> 25)) + b;
////    d += ((a & b) | (~a & c)) + x.array[5] + 0x4787c62a; /* 6 */
////    d = ((d << 12) | (d >>> 20)) + a;
////    c += ((d & a) | (~d & b)) + x.array[6] + 0xa8304613; /* 7 */
////    c = ((c << 17) | (c >>> 15)) + d;
////    b += ((c & d) | (~c & a)) + x.array[7] + 0xfd469501; /* 8 */
////    b = ((b << 22) | (b >>> 10)) + c;
////
////    a += ((b & c) | (~b & d)) + x.array[8] + 0x698098d8; /* 9 */
////    a = ((a << 7) | (a >>> 25)) + b;
////    d += ((a & b) | (~a & c)) + x.array[9] + 0x8b44f7af; /* 10 */
////    d = ((d << 12) | (d >>> 20)) + a;
////    c += ((d & a) | (~d & b)) + x.array[10] + 0xffff5bb1; /* 11 */
////    c = ((c << 17) | (c >>> 15)) + d;
////    b += ((c & d) | (~c & a)) + x.array[11] + 0x895cd7be; /* 12 */
////    b = ((b << 22) | (b >>> 10)) + c;
////
////    a += ((b & c) | (~b & d)) + x.array[12] + 0x6b901122; /* 13 */
////    a = ((a << 7) | (a >>> 25)) + b;
////    d += ((a & b) | (~a & c)) + x.array[13] + 0xfd987193; /* 14 */
////    d = ((d << 12) | (d >>> 20)) + a;
////    c += ((d & a) | (~d & b)) + x.array[14] + 0xa679438e; /* 15 */
////    c = ((c << 17) | (c >>> 15)) + d;
////    b += ((c & d) | (~c & a)) + x.array[15] + 0x49b40821; /* 16 */
////    b = ((b << 22) | (b >>> 10)) + c;
////
////    /* Round 2 */
////    a += ((b & d) | (c & ~d)) + x.array[1] + 0xf61e2562; /* 17 */
////    a = ((a << 5) | (a >>> 27)) + b;
////    d += ((a & c) | (b & ~c)) + x.array[6] + 0xc040b340; /* 18 */
////    d = ((d << 9) | (d >>> 23)) + a;
////    c += ((d & b) | (a & ~b)) + x.array[11] + 0x265e5a51; /* 19 */
////    c = ((c << 14) | (c >>> 18)) + d;
////    b += ((c & a) | (d & ~a)) + x.array[0] + 0xe9b6c7aa; /* 20 */
////    b = ((b << 20) | (b >>> 12)) + c;
////
////    a += ((b & d) | (c & ~d)) + x.array[5] + 0xd62f105d; /* 21 */
////    a = ((a << 5) | (a >>> 27)) + b;
////    d += ((a & c) | (b & ~c)) + x.array[10] + 0x02441453; /* 22 */
////    d = ((d << 9) | (d >>> 23)) + a;
////    c += ((d & b) | (a & ~b)) + x.array[15] + 0xd8a1e681; /* 23 */
////    c = ((c << 14) | (c >>> 18)) + d;
////    b += ((c & a) | (d & ~a)) + x.array[4] + 0xe7d3fbc8; /* 24 */
////    b = ((b << 20) | (b >>> 12)) + c;
////
////    a += ((b & d) | (c & ~d)) + x.array[9] + 0x21e1cde6; /* 25 */
////    a = ((a << 5) | (a >>> 27)) + b;
////    d += ((a & c) | (b & ~c)) + x.array[14] + 0xc33707d6; /* 26 */
////    d = ((d << 9) | (d >>> 23)) + a;
////    c += ((d & b) | (a & ~b)) + x.array[3] + 0xf4d50d87; /* 27 */
////    c = ((c << 14) | (c >>> 18)) + d;
////    b += ((c & a) | (d & ~a)) + x.array[8] + 0x455a14ed; /* 28 */
////    b = ((b << 20) | (b >>> 12)) + c;
////
////    a += ((b & d) | (c & ~d)) + x.array[13] + 0xa9e3e905; /* 29 */
////    a = ((a << 5) | (a >>> 27)) + b;
////    d += ((a & c) | (b & ~c)) + x.array[2] + 0xfcefa3f8; /* 30 */
////    d = ((d << 9) | (d >>> 23)) + a;
////    c += ((d & b) | (a & ~b)) + x.array[7] + 0x676f02d9; /* 31 */
////    c = ((c << 14) | (c >>> 18)) + d;
////    b += ((c & a) | (d & ~a)) + x.array[12] + 0x8d2a4c8a; /* 32 */
////    b = ((b << 20) | (b >>> 12)) + c;
////
////    /* Round 3 */
////    a += (b ^ c ^ d) + x.array[5] + 0xfffa3942; /* 33 */
////    a = ((a << 4) | (a >>> 28)) + b;
////    d += (a ^ b ^ c) + x.array[8] + 0x8771f681; /* 34 */
////    d = ((d << 11) | (d >>> 21)) + a;
////    c += (d ^ a ^ b) + x.array[11] + 0x6d9d6122; /* 35 */
////    c = ((c << 16) | (c >>> 16)) + d;
////    b += (c ^ d ^ a) + x.array[14] + 0xfde5380c; /* 36 */
////    b = ((b << 23) | (b >>> 9)) + c;
////
////    a += (b ^ c ^ d) + x.array[1] + 0xa4beea44; /* 37 */
////    a = ((a << 4) | (a >>> 28)) + b;
////    d += (a ^ b ^ c) + x.array[4] + 0x4bdecfa9; /* 38 */
////    d = ((d << 11) | (d >>> 21)) + a;
////    c += (d ^ a ^ b) + x.array[7] + 0xf6bb4b60; /* 39 */
////    c = ((c << 16) | (c >>> 16)) + d;
////    b += (c ^ d ^ a) + x.array[10] + 0xbebfbc70; /* 40 */
////    b = ((b << 23) | (b >>> 9)) + c;
////
////    a += (b ^ c ^ d) + x.array[13] + 0x289b7ec6; /* 41 */
////    a = ((a << 4) | (a >>> 28)) + b;
////    d += (a ^ b ^ c) + x.array[0] + 0xeaa127fa; /* 42 */
////    d = ((d << 11) | (d >>> 21)) + a;
////    c += (d ^ a ^ b) + x.array[3] + 0xd4ef3085; /* 43 */
////    c = ((c << 16) | (c >>> 16)) + d;
////    b += (c ^ d ^ a) + x.array[6] + 0x04881d05; /* 44 */
////    b = ((b << 23) | (b >>> 9)) + c;
////
////    a += (b ^ c ^ d) + x.array[9] + 0xd9d4d039; /* 33 */
////    a = ((a << 4) | (a >>> 28)) + b;
////    d += (a ^ b ^ c) + x.array[12] + 0xe6db99e5; /* 34 */
////    d = ((d << 11) | (d >>> 21)) + a;
////    c += (d ^ a ^ b) + x.array[15] + 0x1fa27cf8; /* 35 */
////    c = ((c << 16) | (c >>> 16)) + d;
////    b += (c ^ d ^ a) + x.array[2] + 0xc4ac5665; /* 36 */
////    b = ((b << 23) | (b >>> 9)) + c;
////
////    /* Round 4 */
////    a += (c ^ (b | ~d)) + x.array[0] + 0xf4292244; /* 49 */
////    a = ((a << 6) | (a >>> 26)) + b;
////    d += (b ^ (a | ~c)) + x.array[7] + 0x432aff97; /* 50 */
////    d = ((d << 10) | (d >>> 22)) + a;
////    c += (a ^ (d | ~b)) + x.array[14] + 0xab9423a7; /* 51 */
////    c = ((c << 15) | (c >>> 17)) + d;
////    b += (d ^ (c | ~a)) + x.array[5] + 0xfc93a039; /* 52 */
////    b = ((b << 21) | (b >>> 11)) + c;
////
////    a += (c ^ (b | ~d)) + x.array[12] + 0x655b59c3; /* 53 */
////    a = ((a << 6) | (a >>> 26)) + b;
////    d += (b ^ (a | ~c)) + x.array[3] + 0x8f0ccc92; /* 54 */
////    d = ((d << 10) | (d >>> 22)) + a;
////    c += (a ^ (d | ~b)) + x.array[10] + 0xffeff47d; /* 55 */
////    c = ((c << 15) | (c >>> 17)) + d;
////    b += (d ^ (c | ~a)) + x.array[1] + 0x85845dd1; /* 56 */
////    b = ((b << 21) | (b >>> 11)) + c;
////
////    a += (c ^ (b | ~d)) + x.array[8] + 0x6fa87e4f; /* 57 */
////    a = ((a << 6) | (a >>> 26)) + b;
////    d += (b ^ (a | ~c)) + x.array[15] + 0xfe2ce6e0; /* 58 */
////    d = ((d << 10) | (d >>> 22)) + a;
////    c += (a ^ (d | ~b)) + x.array[6] + 0xa3014314; /* 59 */
////    c = ((c << 15) | (c >>> 17)) + d;
////    b += (d ^ (c | ~a)) + x.array[13] + 0x4e0811a1; /* 60 */
////    b = ((b << 21) | (b >>> 11)) + c;
////
////    a += (c ^ (b | ~d)) + x.array[4] + 0xf7537e82; /* 61 */
////    a = ((a << 6) | (a >>> 26)) + b;
////    d += (b ^ (a | ~c)) + x.array[11] + 0xbd3af235; /* 62 */
////    d = ((d << 10) | (d >>> 22)) + a;
////    c += (a ^ (d | ~b)) + x.array[2] + 0x2ad7d2bb; /* 63 */
////    c = ((c << 15) | (c >>> 17)) + d;
////    b += (d ^ (c | ~a)) + x.array[9] + 0xeb86d391; /* 64 */
////    b = ((b << 21) | (b >>> 11)) + c;
//
//    state1.state.array[0] += a;
//    state1.state.array[1] += b;
//    state1.state.array[2] += c;
//    state1.state.array[3] += d;
//    System.gc();
//  }
//
//  /**
//   * Updates hash with the bytebuffer given (using at maximum length bytes from
//   * that buffer)
//   * 
//   * @param stat
//   *          Which state is updated
//   * @param buffer
//   *          Array of bytes to be hashed
//   * @param offset
//   *          Offset to buffer array
//   * @param length
//   *          Use at maximum `length' bytes (absolute maximum is buffer.length)
//   */
//  private void updatePrivate(MD5State stat, ByteArray buffer, int offset, int length) {
//    int index, partlen, i, start;
//    finals = null;
//    /* Length can be told to be shorter, but not inter */
//    if ((length - offset) > buffer.len()) {
//      length = buffer.len() - offset;
//    }
//
//    /* compute number of bytes mod 64 */
//
//    index = stat.count & 0x3f;
//    stat.count += length;
//
//    partlen = 64 - index;
//
//    if (length >= partlen) {
//      // update state (using only Java) to reflect input
//      IntArray decode_buf = IntArray.create(16);
//      if (partlen == 64) {
//        partlen = 0;
//      } else {
//        for (i = 0; i < partlen; i++) {
//          stat.buffer.array[i + index] = buffer.get(i + offset);
//        }
//        transform(stat, stat.buffer, 0, decode_buf);
//      }
//      for (i = partlen; (i + 63) < length; i += 64) {
//        transform(stat, buffer, i + offset, decode_buf);
//      }
//      index = 0;
//    } else {
//      i = 0;
//    }
//    /* buffer remaining input */
//    if (i < length) {
//      start = i;
//      for (; i < length; i++) {
//        stat.buffer.array[index + i - start] = buffer.get(i + offset);
//      }
//    }
//  }
//
//  private static ByteArray encode(final IntArray input, final int len) {
//    int i, j;
//    byte out1[];
//    out1 = new byte[len];
//    for (i = j = 0; j < len; i++, j += 4) {
//      out1[j] = (byte) (input.array[i] & 0xff);
//      out1[j + 1] = (byte) ((input.array[i] >>> 8) & 0xff);
//      out1[j + 2] = (byte) ((input.array[i] >>> 16) & 0xff);
//      out1[j + 3] = (byte) ((input.array[i] >>> 24) & 0xff);
//    }
//    return new ByteArray(out1, len);
//  }
//
//  public MD5(ByteArray data) {
//    state = new MD5State();
//    finals = null;
//    update(data);
//  }
//
//  /**
//   * Updates hash with given array of bytes
//   * 
//   * @param buffer
//   *          Array of bytes to use for updating the hash
//   */
//  public final void update(final ByteArray buffer) {
//    if (buffer == null) {
//      return;
//    }
//    this.state = new MD5State();
//    updatePrivate(state, buffer, 0, buffer.len());
//  }
//
//  /**
//   * Returns array of bytes (16 bytes) representing hash as of the current state
//   * of this object. Note: getting a hash does not invalidate the hash object,
//   * it only creates a copy of the real state which is finalized.
//   * 
//   * @return Array of 16 bytes, the hash of all updated bytes
//   */
//  public synchronized final ByteArray doFinal() {
//    ByteArray bits;
//    int index, padlen;
//    MD5State fin;
//    if (finals == null) {
//      fin = MD5State.createMD5State(state);
//      IntArray count_ints = new IntArray(new int[] {fin.count << 3, fin.count >> 29}, 2);
//      bits = encode(count_ints, 8);
//      index = fin.count & 0x3f;
//      padlen = (index < 56) ? (56 - index) : (120 - index);
//      updatePrivate(fin, padding, 0, padlen);
//      updatePrivate(fin, bits, 0, 8);
//      /* Update() sets finals to null */
//      finals = fin;
//    }
//
//    return encode(finals.state, 16);
//  }
//
//  /**
//   * Returns 32-character hex representation of this objects hash
//   * 
//   * @return String of this object's hash
//   */
//  public static String toHex(final ByteArray hash) {
//    CharArray buf = CharArray.create(hash.len() * 2);
//    for (int i = 0, x = 0; i < hash.len(); i++) {
//      buf.array.setCharAt(x++, HEX_CHARS.charAt((hash.array[i] >>> 4) & 0xf));
//      buf.array.setCharAt(x++, HEX_CHARS.charAt(hash.array[i] & 0xf));
//    }
//    return buf.array.toString();
//  }
//
//  public static String toBase64(final ByteArray data) {
//    CharArray alphabet = new CharArray(new StringBuffer("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="));
//    CharArray out1 = CharArray.create(((data.len() + 2) / 3) * 4);
//    for (int i = 0, index = 0; i < data.len(); i += 3, index += 4) {
//      boolean quad = false;
//      boolean trip = false;
//
//      int val = (0xFF & data.array[i]);
//      val <<= 8;
//      if ((i + 1) < data.len()) {
//        val |= (0xFF & data.array[i + 1]);
//        trip = true;
//      }
//      val <<= 8;
//      if ((i + 2) < data.len()) {
//        val |= (0xFF & data.array[i + 2]);
//        quad = true;
//      }
//      out1.array.setCharAt(index + 3, alphabet.array.charAt(quad ? (val & 0x3F) : 64));
//      val >>= 6;
//      out1.array.setCharAt(index + 2, alphabet.array.charAt(trip ? (val & 0x3F) : 64));
//      val >>= 6;
//      out1.array.setCharAt(index + 1, alphabet.array.charAt(val & 0x3F));
//      val >>= 6;
//      out1.array.setCharAt(index + 0, alphabet.array.charAt(val & 0x3F));
//    }
//    return GameStringUtils.getStringForCharArray(out1);
//  }
//
//  /**
//   * Calculates and returns the hash of the contents of the given file.
//   */
//  public final ByteArray fingerprint(final ByteArray data) {
//    update(data);
//    return doFinal();
//  }
//
//  /**
//   * @return true iff the first 16 bytes of both hash1 and hash2 are equal; both
//   *         hash1 and hash2 are null; or either hash array is less than 16
//   *         bytes in length and their lengths and all of their bytes are equal.
//   */
//  public static boolean equals(ByteArray hash1, ByteArray hash2) {
//    if (hash1 == null) {
//      return hash2 == null;
//    }
//    if (hash2 == null) {
//      return false;
//    }
//    int targ = 16;
//    if (hash1.len() < 16) {
//      if (hash2.len() != hash1.len()) {
//        return false;
//      }
//      targ = hash1.len();
//    } else if (hash2.len() < 16) {
//      return false;
//    }
//    for (int i = 0; i < targ; i++) {
//      if (hash1.get(i) != hash2.get(i)) {
//        return false;
//      }
//    }
//    return true;
//  }
}
